package com.myk.game.gobangchess.rooms.oldrooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.TextSign;

import java.util.*;

/**
 * 下沉四子棋
 */
public class DownConnect4Room extends Room {

    private static final int millisecondForAnimation = 300;

    enum Direction {
        UNKNOWN, UP, DOWN, LEFT, RIGHT
    }

    private Direction curGravity = Direction.DOWN;

    public DownConnect4Room(String roomName) {
        super(roomName, "脑王上的下沉四子棋", "下沉四子棋",BoardStyleData.getGoBangStyle(8,8), true, true);
    }

    @Override
    public String getRuleText() {
        return "黑白双方轮流行动：\n" +
                "落子（棋子会向下跌落）\n" +
                "若下行满了，此行所有的棋子消失，剩下的棋盘则往下沉一行。\n" +
                "\n" +
                "获胜条件：行动后，形成己方四子一线\n" +
                "若棋手落棋时，下行满了但同时在此行将四个棋子连成一条直线，则算是例外：一行消失的规则无效而摆棋的玩家为胜";
    }

    @Override
    public String getCoordMode() {
        return "33330000";
    }

    @Override
    protected void onStartPrepare() {
        this.curGravity = Direction.DOWN; //初始默认引力向下
        //this.updateGravity(curGravity); //为了显示墙的方向
        noticeBlackMove(); //通知黑方先行
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (curGrids[row][col] == 0) {
            signList.clear();
            signList.add(new AroundSign(getIndex(row, col), "#00000000", "#6600FF00", 1.2f));
            curGrids[row][col] = value; //落子位置
        } else {
            // 下的位置已经有棋子了
            return;
        }

        noticeNoMove();

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                updateBoard();// 刷新棋盘
                noticeAllRefreshGameInfo(); //走完后要刷新一下，否则大家看不到最终结局
                if (!checkWin(value)) {
                    if(ifLastLineFull()){
                        signList.add(new GroundSign(getIndex(gridRowMax(), 0),getIndex(gridRowMax(), gridColMax()), "#990000FF", "#660000FF", 1.2f,0,0));
                        new Timer().schedule(new TimerTask() {
                            @Override
                            public void run() {
                                fallDownBoard(); //下沉棋盘
                                changeMover(value); //切换行动方
                            }
                        },millisecondForAnimation);
                    }
                    else {
                        changeMover(value);//切换行动方
                    }
                }
            }
        }, millisecondForAnimation);
    }

    //切换行动方
    private void changeMover(int value) {
        if (value == 1) {
            stepAdd();
            noticeWhiteMove();
        } else if (value == 2) {
            stepAdd();
            noticeBlackMove();
        }
    }

    //如果最后一行满了
    private boolean ifLastLineFull() {
        for (int i = gridColMin(); i <= gridColMax(); i++) {
            if (curGrids[gridRowMax()][i] == 0) {
                return false;
            }
        }
        return true;
    }

    //下沉棋盘
    private void fallDownBoard() {
        for (int row = gridRowMax(); row > gridRowMin(); row--) {
            for (int col = gridColMin(); col <= gridColMax(); col++) {
                curGrids[row][col] = curGrids[row-1][col];
            }
        }
        for (int col = gridColMin(); col <= gridColMax(); col++) {
            curGrids[0][col] = 0;
        }
    }

    // 棋盘row能达到的小边界
    protected int gridRowMin() {
        return 0;
    }

    // 棋盘row能达到的大边界
    protected int gridRowMax() {
        return curGrids.length - 1;
    }

    // 棋盘col能达到的小边界
    protected int gridColMin() {
        return 0;
    }

    // 棋盘col能达到的大边界
    protected int gridColMax() {
        return curGrids[0].length - 1;
    }

    // 判断位置在棋盘上
    private boolean isInGrids(int row, int col) {
        return row >= gridRowMin() && row <= gridRowMax() && col >= gridColMin() && col <= gridColMax();
    }

    // 交换棋盘上两个棋子的位置
    private void swapInGrids(int r1, int c1, int r2, int c2) {
        int tmp = curGrids[r1][c1];
        curGrids[r1][c1] = curGrids[r2][c2];
        curGrids[r2][c2] = tmp;
    }

    // 根据 this.curGravity 更新棋盘
    private void updateBoard() {
        switch (this.curGravity) {
            case DOWN:
                for (int col = gridColMin(); col <= gridColMax(); col++) {
                    int p1 = gridRowMax();
                    int p2 = p1;
                    while (p2 >= gridRowMin()) {
                        if (curGrids[p2][col] != 0) {
                            this.swapInGrids(p1, col, p2, col);
                            p1--;
                        }
                        p2--;
                    }
                }
                break;
            case UP:
                for (int col = gridColMin(); col <= gridColMax(); col++) {
                    int p1 = gridRowMin();
                    int p2 = p1;
                    while (p2 <= gridRowMax()) {
                        if (curGrids[p2][col] != 0) {
                            this.swapInGrids(p1, col, p2, col);
                            p1++;
                        }
                        p2++;
                    }
                }
                break;
            case LEFT:
                for (int row = gridRowMin(); row <= gridRowMax(); row++) {
                    int p1 = gridColMin();
                    int p2 = p1;
                    while (p2 <= gridColMax()) {
                        if (curGrids[row][p2] != 0) {
                            this.swapInGrids(row, p1, row, p2);
                            p1++;
                        }
                        p2++;
                    }
                }
                break;
            case RIGHT:
                for (int row = gridRowMin(); row <= gridRowMax(); row++) {
                    int p1 = gridColMax();
                    int p2 = p1;
                    while (p2 >= gridColMin()) {
                        if (curGrids[row][p2] != 0) {
                            this.swapInGrids(row, p1, row, p2);
                            p1--;
                        }
                        p2--;
                    }
                }
                break;
            default:
                // 应该是不会到这儿的
                //System.out.println("更新棋盘时方向出错啦！");
        }
    }

    protected int getJudgeLength(int x, int y, int dx, int dy) {
        int value = curGrids[x][y];
        int length = 0;
        while (isInGrids(x, y)) {
            if (curGrids[x][y] != value) {
                return length;
            }
            length++;
            x += dx;
            y += dy;
        }
        return length;
    }

    public boolean checkWin(int value) {
        boolean bH4 = false;
        boolean wH4 = false;
        boolean gridFull = true;
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) {
                    continue;
                }
                for (int x = gridRowMin(); x <= gridRowMax(); x++) {
                    for (int y = gridColMin(); y <= gridColMax(); y++) {
                        if (curGrids[x][y] == 0) {
                            gridFull = false;
                        }
                        int len = getJudgeLength(x, y, dx, dy) + getJudgeLength(x, y, -dx, -dy) - 1;
                        if (len == 4) {
                            if (curGrids[x][y] == 1) {
                                bH4 = true;
                            } else if (curGrids[x][y] == 2) {
                                wH4 = true;
                            }
                        }
                    }
                }
            }
        }

        if (bH4 && wH4){
            if (value == 1){
                doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
            }
            else {
                doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
            }
        }
        else if (bH4){
            doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
        }
        else if (wH4){
            doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
        }
        else if (gridFull){
            doOver(WinMode.BOTH_DRAW, player_black.getNickNameOrTemp() + "-黑棋战平" + player_white.getNickNameOrTemp() + "-白棋");
        }
        else {
            return false;
        }
        return true;
    }

}
